package crypto

import (
	"hash"

	"crypto/md5"
	"crypto/sha1"
	"crypto/sha256"
	"crypto/sha512"

	"golang.org/x/crypto/blake2b"
	"golang.org/x/crypto/blake2s"
	"golang.org/x/crypto/md4"
	"golang.org/x/crypto/ripemd160"
	"golang.org/x/crypto/sha3"
)

func NewHash() *hashHelper {
	return &hashHelper{
		hashType: 0, // 0 Blake2s-256 1 Blake2s-128
		hashSize: 32,
		key:      nil,
		b:        nil,
		n:        nil,
		s:        nil,
	}
}

type hashHelper struct {
	hashType int
	hashSize int
	key      []byte
	b        []byte
	n        []byte
	s        []byte
}

func (r *hashHelper) Type(hashType int) *hashHelper {
	r.hashType = hashType

	return r
}
func (r *hashHelper) Size(size int) *hashHelper {
	r.hashSize = size

	return r
}
func (r *hashHelper) Key(key []byte) *hashHelper {
	r.key = key

	return r
}
func (r *hashHelper) B(b []byte) *hashHelper {
	r.b = b

	return r
}

// Ripemd160
// b
func (r *hashHelper) Ripemd160(source []byte) []byte {
	hasher := ripemd160.New()

	_, err := hasher.Write(source)
	if err != nil {
		panic(err)
	}

	return hasher.Sum(r.b)
}

// Blake2b Blake2s # Blake2
// hashSize
// hashType
// key
// b
func (r *hashHelper) Blake2b(source []byte) []byte {
	hasher, err := blake2b.New(r.hashSize, r.key)
	if err != nil {
		panic(err)
	}

	_, err = hasher.Write(source)
	if err != nil {
		panic(err)
	}

	return hasher.Sum(r.b)
}
func (r *hashHelper) Blake2s(source []byte) []byte {
	var hasher hash.Hash
	var err error

	if r.hashType == 1 {
		hasher, err = blake2s.New128(r.key)
	} else {
		hasher, err = blake2s.New256(r.key)
	}
	if err != nil {
		panic(err)
	}

	hasher.Write(source)

	return hasher.Sum(r.b)
}

// Md4
// b
func (r *hashHelper) Md4(source []byte) []byte {
	hasher := md4.New()
	hasher.Write(source)
	return hasher.Sum(r.b)
}

// Md5
// b
func (r *hashHelper) Md5(source []byte) []byte {
	hasher := md5.New()
	hasher.Write(source)
	return hasher.Sum(r.b)
	// hasher := md5.Sum(source)
	// return hasher[:]
}

// Sha1
// b
func (r *hashHelper) Sha1(source []byte) []byte {
	hasher := sha1.New()
	hasher.Write(source)
	return hasher.Sum(r.b)
	// hasher := sha1.Sum(source)
	// return hasher[:]
}

// Sha256 Sha224
// b
func (r *hashHelper) Sha256(source []byte) []byte {
	hasher := sha256.New()
	hasher.Write(source)
	return hasher.Sum(r.b)
}
func (r *hashHelper) Sha224(source []byte) []byte {
	hasher := sha256.New224()
	hasher.Write(source)
	return hasher.Sum(r.b)
}

// Sha512 Sha384 Sha512_224 Sha512_256
// b
func (r *hashHelper) Sha512(source []byte) []byte {
	hasher := sha512.New()
	hasher.Write(source)
	return hasher.Sum(r.b)
}
func (r *hashHelper) Sha384(source []byte) []byte {
	hasher := sha512.New384()
	hasher.Write(source)
	return hasher.Sum(r.b)
}
func (r *hashHelper) Sha512_224(source []byte) []byte {
	hasher := sha512.New512_224()
	hasher.Write(source)
	return hasher.Sum(r.b)
}
func (r *hashHelper) Sha512_256(source []byte) []byte {
	hasher := sha512.New512_256()
	hasher.Write(source)
	return hasher.Sum(r.b)
}

// Sha3_224 Sha3_256 Sha3_384 Sha3_512 Sha3_LegacyKeccak256 Sha3_LegacyKeccak512
// b
func (r *hashHelper) Sha3_224(source []byte) []byte {
	hasher := sha3.New224()
	hasher.Write(source)
	return hasher.Sum(r.b)
}
func (r *hashHelper) Sha3_256(source []byte) []byte {
	hasher := sha3.New256()
	hasher.Write(source)
	return hasher.Sum(r.b)
}
func (r *hashHelper) Sha3_384(source []byte) []byte {
	hasher := sha3.New384()
	hasher.Write(source)
	return hasher.Sum(r.b)
}
func (r *hashHelper) Sha3_512(source []byte) []byte {
	hasher := sha3.New512()
	hasher.Write(source)
	return hasher.Sum(r.b)
}
func (r *hashHelper) Sha3_LegacyKeccak256(source []byte) []byte {
	hasher := sha3.NewLegacyKeccak256()
	hasher.Write(source)
	return hasher.Sum(r.b)
}
func (r *hashHelper) Sha3_LegacyKeccak512(source []byte) []byte {
	hasher := sha3.NewLegacyKeccak512()
	hasher.Write(source)
	return hasher.Sum(r.b)
}

// Sha3_Shake128 Sha3_Shake256
// n
// s
func (r *hashHelper) Sha3_Shake128(source []byte) []byte {
	result := make([]byte, 100)

	// hasher := sha3.NewShake128()
	hasher := sha3.NewCShake128(r.n, r.s)

	_, err := hasher.Write(source)
	if err != nil {
		panic(err)
	}

	n, err := hasher.Read(result)
	if err != nil {
		panic(err)
	}

	return result[:n]

	// sha3.ShakeSum128(source, result)

	// return result
}
func (r *hashHelper) Sha3_Shake256(source []byte) []byte {
	result := make([]byte, 100)

	// hasher := sha3.NewShake256()
	hasher := sha3.NewCShake256(r.n, r.s)

	_, err := hasher.Write(source)
	if err != nil {
		panic(err)
	}

	n, err := hasher.Read(result)
	if err != nil {
		panic(err)
	}

	return result[:n]

	// sha3.ShakeSum256(source, result)
	//
	// return result
}
